﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;

namespace Songhay.Data.Common
{
    /// <summary>
    /// A few static helper members
    /// for <see cref="System.Data.Common.DbParameter"/>
    /// and selected <c>System.Data</c> interfaces.
    /// </summary>
    static public class CommonParameter
    {
        /// <summary>
        /// Gets a parameter.
        /// </summary>
        /// <param name="dbmsCommand">The <see cref="System.Data.Common.DbCommand"/>.</param>
        /// <param name="parameterName">The name of the Parameter.</param>
        /// <param name="parameterValue">The value of the Parameter.</param>
        /// <returns>Returns a <see cref="System.Data.Common.DbParameter"/>.</returns>
        public static DbParameter GetParameter(DbCommand dbmsCommand, String parameterName, Object parameterValue)
        {
            return GetParameter(dbmsCommand as IDbCommand, parameterName, parameterValue) as DbParameter;
        }

        /// <summary>
        /// Gets a parameter.
        /// </summary>
        /// <param name="dbmsCommand">The object implementing <see cref="System.Data.IDbCommand"/>.</param>
        /// <param name="parameterName">The name of the Parameter.</param>
        /// <param name="parameterValue">The value of the Parameter.</param>
        /// <returns>Returns an object implementing <see cref="System.Data.IDataParameter"/>.</returns>
        public static IDataParameter GetParameter(IDbCommand dbmsCommand, String parameterName, Object parameterValue)
        {
            if (dbmsCommand == null) throw new ArgumentNullException("dbmsCommand", "The implementing Data Command is null.");

            IDataParameter param = dbmsCommand.CreateParameter();
            param.ParameterName = parameterName;
            param.Value = parameterValue;
            return param;
        }

        /// <summary>
        /// Gets a parameter without specifying a value.
        /// </summary>
        /// <param name="dbmsCommand">The <see cref="System.Data.Common.DbCommand"/>.</param>
        /// <param name="parameterName">The name of the Parameter.</param>
        /// <returns>Returns a <see cref="System.Data.Common.DbParameter"/>.</returns>
        public static DbParameter GetParameter(DbCommand dbmsCommand, String parameterName)
        {
            return GetParameter(dbmsCommand as IDbCommand, parameterName) as DbParameter;
        }

        /// <summary>
        /// Gets a parameter without specifying a value.
        /// </summary>
        /// <param name="dbmsCommand">The object implementing <see cref="System.Data.IDbCommand"/>.</param>
        /// <param name="parameterName">The name of the Parameter.</param>
        /// <returns>Returns an object implementing <see cref="System.Data.IDataParameter"/>.</returns>
        public static IDataParameter GetParameter(IDbCommand dbmsCommand, String parameterName)
        {
            if (dbmsCommand == null) throw new ArgumentNullException("dbmsCommand", "The implementing Data Command is null.");

            IDataParameter param = dbmsCommand.CreateParameter();
            param.ParameterName = parameterName;
            return param;
        }

        /// <summary>
        /// Gets a parameter for a <see cref="System.Data.DataSet"/> adapter.
        /// </summary>
        /// <param name="dbmsCommand">The <see cref="System.Data.Common.DbCommand"/>.</param>
        /// <param name="parameterName">The name of the Parameter.</param>
        /// <param name="dataType">The DBMS type of the Parameter.</param>
        /// <param name="parameterSize">The size of the DBMS type.</param>
        /// <param name="parameterDirection">The direction of the  Parameter.</param>
        /// <param name="sourceColumn">The column mapped for the <see cref="System.Data.DataTable"/>.</param>
        /// <param name="rowVersion">The row version for the <see cref="System.Data.DataTable"/>.</param>
        /// <param name="nullableColumn">When true the column in the <see cref="System.Data.DataTable"/> is nullable.</param>
        /// <param name="parameterValue">The value of the Parameter.</param>
        /// <returns>Returns a <see cref="System.Data.Common.DbParameter"/>.</returns>
        public static DbParameter GetParameter(DbCommand dbmsCommand, String parameterName, DbType dataType,
            Int32 parameterSize, ParameterDirection parameterDirection, String sourceColumn,
            DataRowVersion rowVersion, Boolean nullableColumn, Object parameterValue)
        {
            if (dbmsCommand == null) throw new ArgumentNullException("dbmsCommand", "The Common Data Command is null.");

            DbParameter param = dbmsCommand.CreateParameter();
            param.ParameterName = parameterName;
            param.DbType = dataType;
            param.Size = parameterSize;
            param.Direction = parameterDirection;
            param.SourceColumn = sourceColumn;
            param.SourceVersion = rowVersion;
            param.SourceColumnNullMapping = nullableColumn;
            param.Value = parameterValue;
            return param;
        }

        /// <summary>
        /// Gets a parameter for a <see cref="System.Data.DataSet"/> adapter.
        /// </summary>
        /// <param name="dbmsCommand">The <see cref="System.Data.Common.DbCommand"/>.</param>
        /// <param name="parameterName">The name of the Parameter.</param>
        /// <param name="dataType">The DBMS type of the Parameter.</param>
        /// <param name="parameterDirection">The direction of the  Parameter.</param>
        /// <param name="sourceColumn">The column mapped for the <see cref="System.Data.DataTable"/>.</param>
        /// <param name="rowVersion">The row version for the <see cref="System.Data.DataTable"/>.</param>
        /// <param name="parameterValue">The value of the Parameter.</param>
        /// <returns>Returns an object implementing <see cref="System.Data.IDataParameter"/>.</returns>
        public static IDataParameter GetParameter(IDbCommand dbmsCommand, String parameterName, DbType dataType,
            ParameterDirection parameterDirection, String sourceColumn, DataRowVersion rowVersion, Object parameterValue)
        {
            if (dbmsCommand == null) throw new ArgumentNullException("dbmsCommand", "The implementing Data Command is null.");

            IDataParameter param = dbmsCommand.CreateParameter();
            param.ParameterName = parameterName;
            param.DbType = dataType;
            param.Direction = parameterDirection;
            param.SourceColumn = sourceColumn;
            param.SourceVersion = rowVersion;
            param.Value = parameterValue;
            return param;
        }

        /// <summary>
        /// <returns>Lists an array of <see cref="System.Data.Common.DbParameter"/>.</returns>
        /// </summary>
        /// <param name="dbmsCommand">The <see cref="System.Data.Common.DbCommand"/>.</param>
        /// <param name="parameterCollection">A collection of paramters.</param>
        /// <returns>Returns an array of <see cref="System.Data.Common.DbParameter"/>.</returns>
        public static DbParameter[] GetParameters(DbCommand dbmsCommand, Dictionary<String, Object> parameterCollection)
        {
             IDataParameter[] p_idata = GetParameters(dbmsCommand as IDbCommand, parameterCollection);
             return CommonParameter.ConvertAllToDbParameter(p_idata);
        }

        /// <summary>
        /// <returns>Lists an array of objects implementing <see cref="System.Data.IDataParameter"/>.</returns>
        /// </summary>
        /// <param name="dbmsCommand">The object implementing <see cref="System.Data.IDbCommand"/>.</param>
        /// <param name="parameterCollection">A collection of parameters.</param>
        /// <returns>Returns an array of objects implementing <see cref="System.Data.IDataParameter"/>.</returns>
        public static IDataParameter[] GetParameters(IDbCommand dbmsCommand, Dictionary<String, Object> parameterCollection)
        {
            if (parameterCollection == null) throw new ArgumentNullException("parameterCollection", "The Collection of parameters is null.");

            List<IDataParameter> list = new List<IDataParameter>(parameterCollection.Count);
            foreach (KeyValuePair<String, Object> kvp in parameterCollection)
            {
                list.Add(CommonParameter.GetParameter(dbmsCommand, kvp.Key, kvp.Value ?? FrameworkType.SqlDatabaseNull()));
            }
            return list.ToArray();
        }

        /// <summary>
        /// Returns <see cref="System.DBNull"/>
        /// when needed based on the specified type.
        /// </summary>
        /// <typeparam name="TypeOfValue">The specified type.</typeparam>
        /// <param name="parameterValue">The boxed Parameter of the specified type.</param>
        public static object GetParameterValue<TypeOfValue>(object parameterValue)
        {

            return CommonParameter.GetParameterValue<TypeOfValue>(parameterValue, false);
        }

        /// <summary>
        /// Returns <see cref="System.DBNull"/>
        /// when needed based on the specified type.
        /// </summary>
        /// <typeparam name="TypeOfValue">The specified type.</typeparam>
        /// <param name="parameterValue">The boxed Parameter of the specified type.</param>
        /// <param name="returnDbNullForZero">When true, return <see cref="System.DBNull"/> for numeric values.</param>
        public static object GetParameterValue<TypeOfValue>(object parameterValue, bool returnDbNullForZero)
        {
            object o = parameterValue;
            Type t = typeof(TypeOfValue);

            if (parameterValue == null)
            {
                o = FrameworkType.SqlDatabaseNull();
            }
            else if (t.Equals(typeof(DateTime)))
            {
                DateTime dt = (DateTime)parameterValue;

                //CONVENTION: return DbNull for default DateTime (Jan 1900):
                if (dt == default(DateTime)) o = FrameworkType.SqlDatabaseNull();
            }
            else if (t.IsValueType)
            {
                if((default(TypeOfValue).Equals(parameterValue)) && returnDbNullForZero) o = FrameworkType.SqlDatabaseNull();
            }

            return o;
        }

        private static DbParameter[] ConvertAllToDbParameter(IDataParameter[] p_idata)
        {
            DbParameter[] p = Array.ConvertAll<IDataParameter, DbParameter>(p_idata,

                   delegate(IDataParameter from)
                   {
                       DbParameter to = from as DbParameter;
                       return to;
                   }

           );

            return p;
        }
    }
}
